package comm

import (
	"crypto/md5"
	"fmt"
	"imooc.com/demo-lottery/conf"
	"imooc.com/demo-lottery/models"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
)

const (
	COOKIENAME = "lottery_loginuser"
)

// 得到客户端IP地址
func ClientIP(r *http.Request) string {
	host, _, _ := net.SplitHostPort(r.RemoteAddr)
	return host
}

// 跳转到url地址
func Redirect(w http.ResponseWriter, url string) {
	w.Header().Add("Location", url)
	w.WriteHeader(http.StatusFound)
}

func GetLoginUser(r *http.Request) *models.ObjLoginuser {
	c, err := r.Cookie(COOKIENAME)
	if err != nil {
		return nil
	}
	// 解开cookie
	params, err := url.ParseQuery(c.Value)
	if err != nil {
		return nil
	}
	uid, err := strconv.Atoi(params.Get("uid"))
	if err != nil || uid < 1 {
		return nil
	}
	now, err := strconv.Atoi(params.Get("now"))
	// cookie时间超过30天，就认为失效了
	if err != nil || NowUnix()-now > 86400*30 {
		return nil
	}
	loginuser := &models.ObjLoginuser{}
	loginuser.Uid = uid
	loginuser.Username = params.Get("username")
	loginuser.Now = now
	loginuser.Ip = ClientIP(r)
	loginuser.Sign = params.Get("sign")

	// 验证sign是否正确
	sign := createLoginuserSign(loginuser)
	if sign != loginuser.Sign {
		log.Println("func_web GetLoginuser createLoginuserSign "+
			"not sign", sign, loginuser.Sign)
		return nil
	}

	return loginuser
}

func SetLoginuser(w http.ResponseWriter, loginuser *models.ObjLoginuser) {
	// 传过来为kong或uid=1，清空cookie
	if loginuser == nil || loginuser.Uid < 1 {
		c := &http.Cookie{
			Name:   COOKIENAME,
			Value:  "",
			Path:   "/",
			MaxAge: -1,
		}
		http.SetCookie(w, c)
		return
	}

	// 若sign为空就生成1个
	if loginuser.Sign == "" {
		loginuser.Sign = createLoginuserSign(loginuser)
	}
	params := url.Values{}
	params.Add("uid", strconv.Itoa(loginuser.Uid))
	params.Add("username", loginuser.Username)
	params.Add("now", strconv.Itoa(loginuser.Now))
	params.Add("ip", loginuser.Ip)
	params.Add("sign", loginuser.Sign)

	c := &http.Cookie{
		Name:  COOKIENAME,
		Value: params.Encode(),
		Path:  "/",
	}
	http.SetCookie(w, c)
}

// 根据登录用户信息生成加密字符串
func createLoginuserSign(loginuser *models.ObjLoginuser) string {
	// 加密字符串
	str := fmt.Sprintf("uid=%d&username=%s&secret=%s&now=%d",
		loginuser.Uid, loginuser.Username, conf.CookieSecret, loginuser.Now)
	// md5加密，再格式化成字符串
	sign := fmt.Sprintf("%x", md5.Sum([]byte(str)))

	return sign
}
